package com.wsc58888.it.wx.wechat;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Date;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.web.multipart.MultipartFile;

import com.java.st.lib.tools.http.HttpStringResponse;
import com.java.st.lib.tools.io.FileUtil;
import com.java.st.lib.tools.io.URLResourceUtil;
import com.java.st.lib.tools.time.DateFormatUtil;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.WechatPayUploadHttpPost;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;

import lombok.extern.slf4j.Slf4j;

/**
 * Created by wd on 2016/6/28.
 */
@Slf4j
public class WechatPayHttpClientUtil {

	private static CloseableHttpClient client;

	/**
	 * 获取http连接
	 * 
	 * @return
	 */
	public static CloseableHttpClient getCloseableHttpClient() {
		if (client != null) {
			return client;
		}
		try {
			String fileContent = FileUtil.toString(URLResourceUtil.asFile("classpath:apiclient_key.pem"));
			String privKeyPEM = fileContent.replace("-----BEGIN PRIVATE KEY-----\n", "")
					.replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");
			byte[] keyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(privKeyPEM);
			// X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
			// PublicKey privateKey = KeyFactory.getInstance("RSA").generatePublic(keySpec);
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
			PrivateKey privateKey = java.security.KeyFactory.getInstance("RSA").generatePrivate(keySpec);
			String apiV3Key = WechatPayConfig.privateKey;
			AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
					new WechatPay2Credentials(WechatPayConfig.mchId,
							new PrivateKeySigner(WechatPayConfig.mchSerialNo, privateKey)),
					apiV3Key.getBytes("utf-8"));
			WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
					.withMerchant(WechatPayConfig.mchId, WechatPayConfig.mchSerialNo, privateKey)
					.withValidator(new WechatPay2Validator(verifier));
			client = builder.build();
		} catch (Exception e) {
			log.error("初始化WecvhatPayHttlClientBulider失败:{}", e.getMessage());
		}
		return client;
	}

	/**
	 * 获取请求超时等配置
	 *
	 * @return
	 */
	public static RequestConfig getRequestConfig() {
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000) // 连接服务器端超时
//                .setConnectionRequestTimeout(5000) // 从连接池获取连接超时
				.setSocketTimeout(30 * 1000) // 从服务器端获取数据超时
				.build();
		return requestConfig;
	}

	/**
	 * 提交json数据
	 *
	 * @param url
	 * @param requestJson
	 * @return
	 * @throws IOException
	 */
	public static String postJson(String url, String requestJson) throws IOException {
		HttpPost httpPost = new HttpPost(url);
		StringEntity se = new StringEntity(requestJson, "UTF-8");
		se.setContentType("application/json");
		httpPost.setEntity(se);// new StringEntity(requestJson, ContentType.APPLICATION_JSON)
		return getCloseableHttpClient().execute(httpPost, new HttpStringResponse());
	}

	/**
	 * 提交postStream数据
	 *
	 * @param url
	 * @param requestJson
	 * @return
	 * @throws IOException
	 */
	public static String postStream(String url, String requestJson) throws IOException {
		HttpPost httpPost = new HttpPost(url);
		InputStream stream = new ByteArrayInputStream(requestJson.getBytes("utf-8"));
		InputStreamEntity reqEntity = new InputStreamEntity(stream);
		reqEntity.setContentType("application/json");
		httpPost.setEntity(reqEntity);
		httpPost.addHeader("Accept", "application/json");

		return getCloseableHttpClient().execute(httpPost, new HttpStringResponse());
	}

	public static String doGet(String url) throws IOException {
		HttpGet httpGet = new HttpGet(url);
		httpGet.addHeader("Accept", "application/json");
		return getCloseableHttpClient().execute(httpGet, new HttpStringResponse());
	}

	public static String patchStream(String url, String jsonString) throws ClientProtocolException, IOException {
		HttpPatch httpPatch = new HttpPatch(url);
		httpPatch.setHeader("Content-type", "application/json");
		httpPatch.setHeader("Charset", "utf-8");
		httpPatch.setHeader("Accept", "application/json");
		httpPatch.setHeader("Accept-Charset", "utf-8");
		StringEntity data = new StringEntity(jsonString, "utf-8");
		httpPatch.setEntity(data);
		return getCloseableHttpClient().execute(httpPatch, new HttpStringResponse());
	}

	/**
	 * 图片上传（营销）API
	 * 
	 * @param url
	 * @param filePath
	 * @return
	 */
	public static String uploadImage(String url, String filePath) {

		try {
			URI uri = new URI(url);
			// 创建文件
			File file = new File(filePath);
			try (InputStream s1 = new FileInputStream(file)) {
				String sha256 = DigestUtils.sha256Hex(s1);
				try (InputStream s2 = new FileInputStream(file)) {
					WechatPayUploadHttpPost request = new WechatPayUploadHttpPost.Builder(uri)
							.withImage(file.getName(), sha256, s2).build();
					return getCloseableHttpClient().execute(request, new HttpStringResponse());
				} catch (FileNotFoundException e) {
					log.error("微信文件上传失败: 文件不存在2 {}", e.getMessage());
				}
			} catch (FileNotFoundException e) {
				log.error("微信文件上传失败 文件不存在1: {}", e.getMessage());
			}

		} catch (Exception e) {
			log.error("微信文件上传失败: {}", e.getMessage());
		}
		return null;
	}

	public static String uploadImage(String url, InputStream fileInputStream) {
		try {
			URI uri = new URI(url);

			String sha256 = DigestUtils.sha256Hex(fileInputStream);
			WechatPayUploadHttpPost request = new WechatPayUploadHttpPost.Builder(uri)
					.withImage(DateFormatUtil.formatDate("yyyyMMddHHmmss", new Date()), sha256, fileInputStream)
					.build();
			return getCloseableHttpClient().execute(request, new HttpStringResponse());

		} catch (Exception e) {
			log.error("微信文件上传失败: {}", e.getMessage());
		}
		return null;
	}

	public static String uploadImage(String url, FileInputStream fileInputStream) {
		try {
			URI uri = new URI(url);

			String sha256 = DigestUtils.sha256Hex(fileInputStream);
			WechatPayUploadHttpPost request = new WechatPayUploadHttpPost.Builder(uri)
					.withImage(DateFormatUtil.formatDate("yyyyMMddHHmmss", new Date()), sha256, fileInputStream)
					.build();
			return getCloseableHttpClient().execute(request, new HttpStringResponse());

		} catch (Exception e) {
			log.error("微信文件上传失败: {}", e.getMessage());
		}
		return null;
	}

	/**
	 * MultipartFile 转 File
	 * 
	 * @param file
	 * @throws Exception
	 */
	public static File multipartFileToFile(MultipartFile file) throws Exception {
		File toFile = null;
		InputStream ins = null;
		ins = file.getInputStream();
		toFile = new File(file.getOriginalFilename());
		inputStreamToFile(ins, toFile);
		ins.close();
		return toFile;
	}

	public static void inputStreamToFile(InputStream ins, File file) {
		try {
			OutputStream os = new FileOutputStream(file);
			int bytesRead = 0;
			byte[] buffer = new byte[8192];
			while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
				os.write(buffer, 0, bytesRead);
			}
			os.close();
			ins.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static String uploadImage(String url, MultipartFile mFile) {
		try {
			URI uri = new URI(url);
			// 创建文件
			File file = multipartFileToFile(mFile);
			try (InputStream s1 = new FileInputStream(file)) {
				String sha256 = DigestUtils.sha256Hex(s1);
				try (InputStream s2 = new FileInputStream(file)) {
					WechatPayUploadHttpPost request = new WechatPayUploadHttpPost.Builder(uri)
							.withImage(file.getName(), sha256, s2).build();
					return getCloseableHttpClient().execute(request, new HttpStringResponse());
				} catch (FileNotFoundException e) {
					log.error("微信文件上传失败: 文件不存在2 {}", e.getMessage());
				}
			} catch (FileNotFoundException e) {
				log.error("微信文件上传失败 文件不存在1: {}", e.getMessage());
			}

		} catch (Exception e) {
			log.error("微信文件上传失败: {}", e.getMessage());
		}
		return null;
	}

}
